﻿<cfscript>
/** 
* Coldfusion JSON
* 
* @hint "Coldfusion JSON" 
*/ 

component 
	displayname="public.service.util.jsonAdvice" 
	output=false 
	{
	
	/**
	* @hint "初始化对象"
	*/
	public public.service.util.jsonAdvice function init() output=false {
		return this;
	}
	
	/**
	* @hint "JSON 编码"
	* 
	* @data "数据"
	* @queryFormat "查询格式 默认值 query"
	* @queryKeyCase "关键字大小写 lower"
	* @stringNumbers "是否将数字转换为字符串"
	* @formatDates "是否格式化日期"
	* @columnListFormat "列名格式化"
	*/
	public string function encode( required any data, string queryFormat="query", string queryKeyCase="lower", boolean stringNumbers=false, boolean formatDates=false, string columnListFormat="string" ) output=false {
		
		var jsonString = "";
		var tempVal = "";
		var arKeys = "";
		var colPos = 1;
		var i = 1;
		var j = 1;
		var column = "";
		var datakey = "";
		var recordcountkey = "";
		var columnlist = "";
		var columnlistkey = "";
		var dJSONString = "";
		var escapeToVals = "\\,\"",\/,\b,\t,\n,\f,\r";
		var escapeVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#";
		
		var _data = arguments.data;
		
		/* BOOLEAN */
		if (isBoolean(_data) AND NOT isNumeric(_data) AND NOT listFindNoCase("Yes,No", _data)){
			return lCase(toString(_data));
		}
		
		/* NUMBER */
		else if (NOT stringNumbers AND isNumeric(_data) AND NOT reFind("^0+[^\.]",_data)) {
			return toString(_data);
		}
		
		/* DATE */
		else if (isDate(_data) AND arguments.formatDates) {
			return '"#DateFormat(_data, "medium")# #TimeFormat(_data, "medium")#"';
		}
		
		/* STRING */
		else if (isSimpleValue(_data)) {
			return '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"';
		}
		
		/* ARRAY */
		else if (isArray(_data)) {
			
			dJSONString = createObject('java','java.lang.StringBuffer').init("");
			
			for (i=1; i lte arrayLen(_data); i++) {
				tempVal = encode( _data[i], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat );
				if (dJSONString.toString() eq "") {
					dJSONString.append(tempVal);
				}
				else {
					dJSONString.append("," & tempVal);
				}
			}
			
			return "[" & dJSONString.toString() & "]";
			
		}
		
		/* STRUCT */
		else if (isStruct(_data)) {
			
			dJSONString = createObject('java','java.lang.StringBuffer').init("");
			arKeys = structKeyArray(_data);
			
			for (i=1; i lte arrayLen(arKeys); i++) {
				tempVal = encode( _data[ arKeys[i] ], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat );
				if (dJSONString.toString() eq "") {
					dJSONString.append('"' & arKeys[i] & '":' & tempVal);
				}
				else {
					dJSONString.append("," & '"' & arKeys[i] & '":' & tempVal);
				}
			}
			
			return "{" & dJSONString.toString() & "}";
		}
		
		/* QUERY */
		else if (isQuery(_data)) {

			dJSONString = createObject('java','java.lang.StringBuffer').init("");
			
			/* Add query meta data */
			if (arguments.queryKeyCase eq "lower") {
				recordcountKey = "recordcount";
				columnlistKey = "columnlist";
				columnlist = LCase(_data.columnlist);
				dataKey = "data";
			}
			else {
				recordcountKey = "RECORDCOUNT";
				columnlistKey = "COLUMNLIST";
				columnlist = _data.columnlist;
				dataKey = "data";
			}
			
			dJSONString.append('"#recordcountKey#":' & _data.recordcount);
			
			if (arguments.columnListFormat eq "array") {
				columnlist = "[" & ListQualify(columnlist, '"') & "]";
				dJSONString.append(',"#columnlistKey#":' & columnlist);
			}
			else {
				dJSONString.append(',"#columnlistKey#":"' & columnlist & '"');
			}
			dJSONString.append(',"#dataKey#":');
			
			/* Make query a structure of arrays */
			if (arguments.queryFormat eq "query") {
				dJSONString.append("{");
				colPos = 1;
				
				for (j=1; j lte listLen(_data.columnlist,","); j++) {
					
					column = listGetAt(_data.columnlist, j, ",");
					
					if (colPos gt 1) {
						dJSONString.append(",");
					}
					
					if (arguments.queryKeyCase EQ "lower") {
						column = lCase(column);
					}
					
					dJSONString.append('"' & column & '":[');
					
					for (i=1; i lte _data.recordcount; i++) {
						/* Get cell value; recurse to get proper format depending on string/number/boolean data type */
						tempVal = encode( _data[column][i], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat );
						if (i gt 1) {
							dJSONString.append(",");
						}
						dJSONString.append(tempVal);
					}
					
					dJSONString.append("]");
					
					colPos = colPos + 1;
				}
				
				dJSONString.append("}");
				
			}
			/* Make query an array of structures */
			else {
				dJSONString.append("[");
				
				for (i=1; i lte _data.recordcount; i++) {
					
					if (i gt 1) {
						dJSONString.append(",");
					}
					
					dJSONString.append("{");
					colPos = 1;
					
					for (j=1; j lte listLen(_data.columnlist,","); j++) {
						
						column = listGetAt(_data.columnlist, j, ",");
						
						tempVal = encode( _data[column][i], arguments.queryFormat, arguments.queryKeyCase, arguments.stringNumbers, arguments.formatDates, arguments.columnListFormat );
						
						if (colPos GT 1) {
							dJSONString.append(",");
						}
						
						if (arguments.queryKeyCase EQ "lower"){
							column = LCase(column);
						}
						
						dJSONString.append('"' & column & '":' & tempVal);
						
						colPos = colPos + 1;
						
					}
					
					dJSONString.append("}");
					
				}
				
				dJSONString.append("]");
				
			}
			
			/* Wrap all query data into an object */
			return "{" & dJSONString.toString() & "}";
			
		}
		
		/* UNKNOWN OBJECT TYPE */
		else {
			return '"' & "unknown-obj" & '"';
		}
		
	}

}

</cfscript>